<?php

namespace common\components;

use Yii;
use yii\log\DbTarget as YDbTarget;
use yii\log\LogRuntimeException;
use yii\db\Exception;
use yii\helpers\VarDumper;
defined('HOSTNAME') or define('HOSTNAME', gethostname());
class DbTarget extends YDbTarget {

    public $excludeMsgList = ['Input is not proper UTF-8', 'Incorrect string value', 'Data too long for column', 'Insert value list does not match column list', 'Unable to resolve the request', 'Page not found'];
    public $emergencyList  = ['mysql', 'redis', 'Base table or view not found', 'connection refused'];
    public $db             = 'db';
    public $logTable       = 'app_log';

    public function export()
    {
        if ($this->db->getTransaction()) {
            // create new database connection, if there is an open transaction
            // to ensure insert statement is not affected by a rollback
            $this->db = clone $this->db;
        }

        $tableName = $this->db->quoteTableName($this->logTable);
        $sql = "INSERT INTO $tableName ([[appid]], [[level]], [[category]], [[log_time]], [[prefix]], [[message]], [[emergency]])
        VALUES (:appid, :level, :category, :log_time, :prefix, :message, :emergency)";
        $command = $this->db->createCommand($sql);
        foreach ($this->messages as $message) {
            list($text, $level, $category, $timestamp) = $message;
            if ($this->getLevels() && !($this->getLevels() & $message[1])) {
                continue;
            }
            if (!is_string($text)) {
                // exceptions may not be serializable if in the call stack somewhere is a Closure
                if ($text instanceof \Throwable || $text instanceof \Exception) {
                    $text = (string) $text;
                } else {
                    $text = VarDumper::export($text);
                }
            }
            $exclude = false;
            foreach ($this->excludeMsgList as $excludeMsg){
                if(stripos($text, $excludeMsg) !== false){
                    $exclude = true;
                    break;
                }
            }
            if($exclude){
                continue;
            }
            $emergencyStatus = 0;
            foreach ($this->emergencyList as $emergency){
                if(stripos($text, $emergency) !== false){
                    $emergencyStatus = 1;
                    break;
                }
            }
            $user = Yii::$app->has('user', true) ? Yii::$app->get('user') : null;
            if ($user && ($identity = $user->getIdentity(false))) {
                $username = $identity->getName();
            } else {
                $username = '-';
            }
            $text = sprintf("ip:%s==hostname:%s==:%s==%s", Common::getLocalIP(), HOSTNAME, $username, $text);
            $timestamp = $this->getTime($timestamp);
            if ($command->bindValues([
                ':appid' => Yii::$app->id,
                ':level' => $level,
                ':category' => $category,
                ':log_time' => $timestamp,
                ':prefix' => $this->getMessagePrefix($message),
                ':message' => $text,
                ':emergency' => $emergencyStatus
            ])->execute() > 0) {
                continue;
            }
            throw new LogRuntimeException('Unable to export log through database!');
        }
    }
}

